﻿#region
/* ===============================================
 * 作者：guopeng           时间：2012/2/2 21:41:25
 * 
 * 
 * 类描述：
 * 
 * 
 * =============================================== */
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using System.Data;
using System.Collections;
using System.Data.Entity;

namespace ueEngine.Biz.Inf.Entities.DBSupport
{
    public static class ContextExtensions
    {
        public static IEnumerable SqlQueryForDynamic(this Database db, string sql, params object[] parameters)
        {
            IDbConnection defaultConn = new System.Data.SqlClient.SqlConnection();
            return SqlQueryForDynamicOtherDB(db, sql, defaultConn, parameters);
        }
        public static IEnumerable SqlQueryForDynamicOtherDB(this Database db, string sql, IDbConnection conn, params object[] parameters)
        {
            conn.ConnectionString = db.Connection.ConnectionString;
            if (conn.State != ConnectionState.Open)
            {
                conn.Open();
            }
            IDbCommand cmd = conn.CreateCommand();
            cmd.CommandText = sql;
            IDataReader dataReader = cmd.ExecuteReader();
            if (!dataReader.Read())
            {
                return null; //无结果返回Null     
            }
            #region 构建动态字段
            TypeBuilder builder = ContextExtensions.CreateTypeBuilder(
                "EF_DynamicModelAssembly",
                "DynamicModule",
                "DynamicType");
            int fieldCount = dataReader.FieldCount;
            for (int i = 0; i < fieldCount; i++)
            {
                //dic.Add(i, dataReader.GetName(i));        
                //Type type = dataReader.GetFieldType(i);      
                ContextExtensions.CreateAutoImplementedProperty(
                    builder,
                    dataReader.GetName(i),
                    dataReader.GetFieldType(i));
            }
            #endregion
            dataReader.Close();
            dataReader.Dispose();
            cmd.Dispose();
            conn.Close();
            conn.Dispose();
            Type returnType = builder.CreateType();
            if (parameters != null)
            {
                return db.SqlQuery(returnType, sql, parameters);
            }
            else
            {
                return db.SqlQuery(returnType, sql);
            }
        }
        private static TypeBuilder CreateTypeBuilder(string assemblyName, string moduleName, string typeName)
        {
            TypeBuilder typeBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
                new AssemblyName(assemblyName),
                AssemblyBuilderAccess.Run).DefineDynamicModule(moduleName).DefineType(typeName, TypeAttributes.Public);
            typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
            return typeBuilder;
        }
        private static void CreateAutoImplementedProperty(
            TypeBuilder builder,
            string propertyName,
            Type propertyType)
        {
            const string PrivateFieldPrefix = "m_";
            const string GetterPrefix = "get_";
            const string SetterPrefix = "set_";
            // Generate the field.           
            FieldBuilder fieldBuilder = builder.DefineField(
                string.Concat(
                PrivateFieldPrefix, propertyName),
                propertyType,
                FieldAttributes.Private);
            // Generate the property        
            PropertyBuilder propertyBuilder = builder.DefineProperty(
                propertyName,
                System.Reflection.PropertyAttributes.HasDefault,
                propertyType, null);
            // Property getter and setter attributes.      
            MethodAttributes propertyMethodAttributes = MethodAttributes.Public
                | MethodAttributes.SpecialName
                | MethodAttributes.HideBySig;
            // Define the getter method.          
            MethodBuilder getterMethod = builder.DefineMethod(
                string.Concat(GetterPrefix, propertyName),
                propertyMethodAttributes,
                propertyType,
                Type.EmptyTypes);
            // Emit the IL code.    
            // ldarg.0           
            // ldfld,_field       
            // ret       
            ILGenerator getterILCode = getterMethod.GetILGenerator();
            getterILCode.Emit(OpCodes.Ldarg_0);
            getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
            getterILCode.Emit(OpCodes.Ret);
            // Define the setter method.       
            MethodBuilder setterMethod = builder.DefineMethod(
                string.Concat(SetterPrefix, propertyName),
                propertyMethodAttributes,
                null,
                new Type[] { propertyType });
            // Emit the IL code.  
            // ldarg.0           
            // ldarg.1           
            // stfld,_field  
            // ret        
            ILGenerator setterILCode = setterMethod.GetILGenerator();
            setterILCode.Emit(OpCodes.Ldarg_0);
            setterILCode.Emit(OpCodes.Ldarg_1);
            setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
            setterILCode.Emit(OpCodes.Ret);
            propertyBuilder.SetGetMethod(getterMethod);
            propertyBuilder.SetSetMethod(setterMethod);
        }

        public static UpdateContext<T> Update<T>(this Context ctx) where T : class
        {
            return new UpdateContext<T>(ctx);
        }

        public static DeleteContext<T> Delete<T>(this Context ctx) where T : class
        {
            return new DeleteContext<T>(ctx);
        }
    }
}
